#pragma once
#include <mqcomm/Log.hpp>
#include <mqcomm/Helper.hpp>
#include <iostream>
#include <string>
#include <memory>
#include <cassert>
#include <mutex>
#include <google/protobuf/map.h>
#include <unordered_map>
using namespace std;


namespace rbmq {
    // 队列类
    struct MsgQueue {
        typedef shared_ptr<MsgQueue> ptr;
        MsgQueue() {}
        MsgQueue(const string& name, bool durable, bool exclusive, bool auto_delete, const google::protobuf::Map<string, string>& args) 
            :_name(name)
            ,_durable(durable)
            ,_exclusive(exclusive)
            ,_auto_delete(auto_delete)
            ,_args(args)
        {}

        string get_args() {
            if (_args.empty()) {
                return "";
            }
            // 将_args中的内容，序列化之后，返回一个字符串
            // 字符串形式: key=val&&key=val
            string ret;
            for (auto it = _args.begin(); it != _args.end(); it++) {
                ret += it->first + "=" + it->second + "&";
            }
            ret.pop_back();
            return ret;
        }

        void SetArgs(const string& args_str) { // 内部会解析args_str，然后放到unordered_map中去
            // key=val&key=val
            // 将字符串分割后，加入到unordered_map中
            vector<string> tokens;
            StringHelper::splitString(args_str, &tokens, "&");
            for (auto& str : tokens) {
                auto pos = str.find("=");
                string key = str.substr(0, pos);
                string val = str.substr(pos + 1);
                _args[key] = val;
            }
        }

        string _name; // 队列名称
        bool _durable; // 是否持久化存储标志
        bool _exclusive; // 是否独占标志
        bool _auto_delete; // 是否自动删除标志
        google::protobuf::Map<string, string> _args; // 其它参数
    };
    // ------------------------------------------------------------------------------------------------------------------------------------
    // 队列持久化管理类
    typedef unordered_map<string, MsgQueue::ptr> QueueMap;
    class MsgQueueMapper {
    public :
        MsgQueueMapper(const string& dbfile) 
            :_sql_helper(dbfile)
        {
            // 创建数据库
            string path = FileHelper::parentDiretoty(dbfile);
            if (FileHelper::createDirectory(path)) {
                _sql_helper.open();
            }
            // 创建表
            createTable();

        }

        // 创建数据库表
        void createTable() {
            const string commd = "create table if not exists queue_table(\
                                    name varchar(32) primary key,\
                                    durable int,\
                                    exclusive int, \
                                    auto_delete int,\
                                    args varchar(128));";
            // 执行语句
            _sql_helper.execute(commd, nullptr, nullptr);
        }
        // 删除数据库表
        void removeTable() {
            const string commd = "drop table queue_table;";
            // 执行语句
            if (!_sql_helper.execute(commd, nullptr, nullptr)) {
                LOG(Debug) << "删除数据库失败!" << endl;
            }
        }
        // 新增数据到表中
        bool insert(MsgQueue::ptr& queue) {
            char commd[1024];
            sprintf(commd, "insert into queue_table values('%s', %d, %d, %d, '%s');", \
            queue->_name.c_str(), queue->_durable, queue->_exclusive, queue->_auto_delete, queue->get_args().c_str());
            // 执行语句
            if (!_sql_helper.execute(commd, nullptr, nullptr)) {
                LOG(Debug) << "插入数据失败!" << endl;
                return false;
            }
            return true;
        }
        // 从表中删除数据
        void remove(const string& name) {
            const string commd = "delete from queue_table where name='" + name + "';";
            // 执行语句
            _sql_helper.execute(commd, nullptr, nullptr);
        }
        // 获取所有队列的信息(便于数据恢复)
        QueueMap recovery() {
            QueueMap result;
            const string commd = "select name, durable, exclusive, auto_delete, args from queue_table;";
            // 执行指令
            if (!_sql_helper.execute(commd, selectCallback, &result)) {
                LOG(Error) << "恢复数据失败!" << endl;
                return QueueMap();
            }
            return result;
        }
    private :
        static int selectCallback(void *arg, int numcol, char** row, char** feilds) {
            QueueMap* result = static_cast<QueueMap*>(arg);
            MsgQueue::ptr queue = make_shared<MsgQueue>();
            queue->_name = row[0];
            queue->_durable = (bool)stoi(row[1]);
            queue->_exclusive = (bool)stoi(row[2]);
            queue->_auto_delete = (bool)stoi(row[3]);
            if (row[4]) {
                queue->SetArgs(row[4]);
            }
            result->insert(make_pair(queue->_name, queue));
            return 0;
        }
    private :  
        SqliteHelper _sql_helper; // 数据库操作句柄
    };

    // ------------------------------------------------------------------------------------------------------------------------------------
    // 队列数据管理器
    class MsgQueueManager {
    public :
        typedef shared_ptr<MsgQueueManager> ptr;
        MsgQueueManager(const string& dbfile) 
            :_mapper(dbfile)
        {
            // 同样的，每次重启之前都要先恢复数据
            unique_lock<mutex> lock(_mutex);
            _queues = _mapper.recovery();
        }

        // 声明一个队列
        bool declareQueue(const string& name, bool durable, bool exclusive, bool auto_delete, const google::protobuf::Map<string, string>& args) {
            unique_lock<mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it != _queues.end()) {
                return true;
            }
            MsgQueue::ptr queue = make_shared<MsgQueue>(name, durable, exclusive, auto_delete, args);
            if (durable == true) {
                _mapper.insert(queue);
            }
            _queues.insert(make_pair(name, queue));
            return true;
        }

        // 删除一个队列
        void deleteQueue(const string& name) {
            unique_lock<mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end()) {
                return;
            }
            if (_queues[name]->_durable == true) {
                _mapper.remove(name);
            }
            _queues.erase(name);
        }

        // 获取一个队列的信息
        MsgQueue::ptr selectQueue(const string& name) {
            unique_lock<mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end()) {
                return MsgQueue::ptr();
            }
            return it->second;
        }

        // 获取所有的队列信息
        const QueueMap getAllQuues() const  {
            //unique_lock<mutex> lock(_mutex);
            return _queues;

        }

        // 判断一个队列是否存在
        bool exists(const string& name) {
            unique_lock<mutex> lock(_mutex);
            auto it = _queues.find(name);
            if (it == _queues.end()) {
                return false;
            }
            return true;
        }
        
        size_t size() {
            return _queues.size();
        }

        // 清理所有的队列
        void clear() {
            unique_lock<mutex> lock(_mutex);
            _mapper.removeTable();
            _queues.clear();
        }

    private :  
        MsgQueueMapper _mapper;
        QueueMap _queues;
        mutex _mutex; // 互斥锁
    };
};
